using System.Collections.Generic;
using System.Linq;
using System.Text;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.I18N;

namespace OracleInternal.BinXml
{
	internal class ObxmlDecodeState : ObxmlStateObject
	{
		private bool m_bInit;

		internal bool m_IsProcessingDTD;

		private bool m_bUseXmlWriterForDTDAndData;

		private ObxmlObjectPool<ObxmlNodeState> m_NodePool = new ObxmlObjectPool<ObxmlNodeState>(0);

		private ObxmlObjectPool<AttributeInfo> m_AttributePool = new ObxmlObjectPool<AttributeInfo>(0);

		private Stack<ObxmlNodeState> m_NodeStates;

		private ObxmlNodeState m_CurrentNode;

		private ObxmlNodeState m_PreviousSibling;

		private List<PrefixInfo> m_NsStack;

		private Dictionary<int, PrefixInfo> m_PrefixTable;

		private Dictionary<int, PrefixInfo> m_NsPrefixTable;

		internal List<AttributeInfo> AttributeList;

		internal DecodeStates DecodeStateMask;

		internal DataOperationTypes CurrentDataOperation;

		internal ObxmlSectionHeader SectionHeader;

		internal ObxmlDocHeader DocHeader;

		private ObxmlDTDInfo m_DTDInfo;

		internal ObxmlInstructionState m_CurrentInstruction;

		internal ObxmlInstructionState m_LastInstruction;

		internal byte[] CurrentCsxBuffer;

		internal byte[] LastCsxBuffer;

		internal bool IsExtendedOpcode;

		internal ObxmlOpcode.OpcodeIds PrtOpcode;

		internal string PrtBuffer;

		internal ObxmlDecodeRequest m_RequestObject;

		internal ObxmlStream m_BinXmlStream;

		internal bool SectionHeaderFound;

		internal ObxmlDecoder Parent;

		internal ObxmlErrorTypes ErrorType;

		internal ObxmlDecodeResponse LastDecodeResult;

		internal bool HasBeginTagClosurePending;

		internal int LastNodeId;

		internal bool ProcessingTokenSet;

		internal ObxmlDTDInfo DTDInfo
		{
			get
			{
				if (m_DTDInfo == null)
				{
					m_DTDInfo = new ObxmlDTDInfo(this);
				}
				return m_DTDInfo;
			}
		}

		internal bool IsInitialized => m_bInit;

		internal bool IsNotSchemaBased => (SectionHeader.Flags & 2) > 0;

		internal bool PerformFullXmlParse
		{
			get
			{
				if (m_DTDInfo != null)
				{
					return m_DTDInfo.IsValid;
				}
				return false;
			}
		}

		internal bool UseXmlWriterForDTDAndData => m_bUseXmlWriterForDTDAndData;

		internal ObxmlTokenMap TokenMap => Parent.TokenMap;

		internal ObxmlDecodeState()
		{
			m_CurrentInstruction = new ObxmlInstructionState(this);
			m_LastInstruction = new ObxmlInstructionState(this);
			CurrentCsxBuffer = null;
			LastCsxBuffer = null;
			PrtOpcode = ObxmlOpcode.OpcodeIds.None;
			PrtBuffer = null;
			LastNodeId = 0;
			m_BinXmlStream = null;
			HasBeginTagClosurePending = false;
			Parent = null;
			ErrorType = ObxmlErrorTypes.Success;
			ResetDecodeStateMaskToNone();
			m_CurrentNode = null;
			m_bInit = false;
			m_PreviousSibling = null;
			m_NodeStates = new Stack<ObxmlNodeState>(50);
			m_NsStack = new List<PrefixInfo>(20);
			m_RequestObject = new ObxmlDecodeRequest();
			SectionHeader = new ObxmlSectionHeader();
			DocHeader = new ObxmlDocHeader();
			LastDecodeResult = new ObxmlDecodeResponse(this);
			m_PrefixTable = new Dictionary<int, PrefixInfo>();
			m_NsPrefixTable = new Dictionary<int, PrefixInfo>();
			CurrentDataOperation = DataOperationTypes.NoData;
			IsExtendedOpcode = false;
			SectionHeaderFound = false;
			AttributeList = new List<AttributeInfo>(100);
			ProcessingTokenSet = false;
		}

		internal void DisposeOutput()
		{
			if (m_RequestObject.m_RequestOutput.IsOutputType(InputOutputTypes.StringBuilder))
			{
				((StringBuilder)m_RequestObject.m_RequestOutput.m_OutputObject).Clear();
				m_RequestObject.m_RequestOutput.m_OutputObject = null;
			}
		}

		internal override void ClearStateObject()
		{
			if (m_bInit)
			{
				if (m_CurrentInstruction != null)
				{
					m_CurrentInstruction.ClearStateObject();
				}
				if (m_LastInstruction != null)
				{
					m_LastInstruction.ClearStateObject();
				}
				CurrentCsxBuffer = null;
				LastCsxBuffer = null;
				PrtOpcode = ObxmlOpcode.OpcodeIds.None;
				PrtBuffer = null;
				LastNodeId = 0;
				if (m_BinXmlStream != null)
				{
					m_BinXmlStream.Dispose();
					m_BinXmlStream = null;
				}
				HasBeginTagClosurePending = false;
				Parent = null;
				ResetDecodeStateMaskToNone();
				ErrorType = ObxmlErrorTypes.Success;
				m_CurrentNode = null;
				m_bInit = false;
				m_PreviousSibling = null;
				if (m_NodeStates != null)
				{
					m_NodeStates.Clear();
				}
				if (m_NsStack != null)
				{
					m_NsStack.Clear();
				}
				if (DTDInfo != null)
				{
					DTDInfo.ClearStateObject();
					DTDInfo.SetDecodeStateObject(this);
				}
				m_RequestObject.ResetRequestObject();
				SectionHeader.ClearStateObject();
				DocHeader.ClearStateObject();
				LastDecodeResult.ResetResponseObject(this);
				if (m_PrefixTable != null)
				{
					m_PrefixTable.Clear();
				}
				if (m_NsPrefixTable != null)
				{
					m_NsPrefixTable.Clear();
				}
				CurrentDataOperation = DataOperationTypes.NoData;
				IsExtendedOpcode = false;
				SectionHeaderFound = false;
				AttributeList.Clear();
				ProcessingTokenSet = false;
				m_NodePool.Purge();
				m_AttributePool.Purge();
			}
		}

		internal void SetObxmlDecodeState(ObxmlDecoder decoder, ObxmlStream stream, ObxmlDecodeResponse lastDecodeResult)
		{
			ClearStateObject();
			Parent = decoder;
			m_BinXmlStream = stream;
			if (lastDecodeResult != null)
			{
				LastDecodeResult = lastDecodeResult;
			}
			Init();
		}

		internal bool IsDecoderStateValid()
		{
			if ((ErrorType == ObxmlErrorTypes.Success || ObxmlErrorTypes.Done == ErrorType) && m_RequestObject != null)
			{
				return m_RequestObject.IsRequestValid();
			}
			return false;
		}

		internal ObxmlNodeState GetNodeState()
		{
			return m_NodePool.Get();
		}

		internal void FreeNodeState(ObxmlNodeState ns)
		{
			m_NodePool.Put(ns);
		}

		internal AttributeInfo GetAttributeInfo()
		{
			return m_AttributePool.Get();
		}

		internal void FreeAttributeInfo(AttributeInfo attrInfo)
		{
			m_AttributePool.Put(attrInfo);
		}

		internal bool TryAppendingBeginTagClosure(ObxmlNodeState ns, bool checkForInitialNode, bool checkForNewNode)
		{
			if (!HasBeginTagClosurePending)
			{
				return false;
			}
			bool flag = HasBeginTagClosurePending;
			if (checkForInitialNode)
			{
				flag = flag && m_NodeStates.Count > 0;
			}
			if (checkForNewNode && ns != null)
			{
				flag = flag && LastNodeId != ns.NodeId;
			}
			if (flag)
			{
				m_CurrentInstruction.AppendElementStartTagClosing(this, bPreviousElement: false);
			}
			return flag;
		}

		internal bool Init()
		{
			if (!m_bInit)
			{
				PushNodeState(new ObxmlNodeState());
				m_bInit = true;
			}
			return m_bInit;
		}

		internal ObxmlNodeState GetLastNodeState()
		{
			if (m_NodeStates.Count != 0)
			{
				return m_NodeStates.Peek();
			}
			return null;
		}

		internal ObxmlNodeState GetCurrentNodeState(bool clone = false)
		{
			if (clone)
			{
				return m_CurrentNode.Clone();
			}
			return m_CurrentNode;
		}

		internal void SetLastInstructionToCurrent(bool resetCurrent, bool copyCsxPartialBuffer = false)
		{
			m_LastInstruction.ResetTo(m_CurrentInstruction, copyCsxPartialBuffer);
			if (resetCurrent)
			{
				m_CurrentInstruction.ClearStateObject();
			}
		}

		internal void SwapLastInstructionToCurrent(bool resetCurrent)
		{
			m_LastInstruction = m_CurrentInstruction;
			if (resetCurrent)
			{
				m_CurrentInstruction = new ObxmlInstructionState(this);
			}
		}

		internal bool HasDecodeState(DecodeStates stateFlag)
		{
			return (stateFlag & DecodeStateMask) == stateFlag;
		}

		internal bool HasMoreElementData()
		{
			if (HasDecodeState(DecodeStates.ElementStart | DecodeStates.ElementDataStart))
			{
				return true;
			}
			return false;
		}

		internal bool HasElementEndPending()
		{
			if (!HasDecodeState(DecodeStates.ElementStart) && HasDecodeState(DecodeStates.ElementEndPending))
			{
				return true;
			}
			return false;
		}

		internal bool HasMoreCsxInstructionData(out long csxDataSize)
		{
			return m_CurrentInstruction.HasMoreCsxInstructionData(out csxDataSize);
		}

		internal bool HasMoreTokenOrData(out long tokenDataSize)
		{
			return m_CurrentInstruction.HasMoreTokenOrData(out tokenDataSize);
		}

		internal void SetDecodeState(DecodeStates stateFlag, bool resetOldMasks = true)
		{
			if (resetOldMasks)
			{
				DecodeStateMask = stateFlag;
			}
			else
			{
				DecodeStateMask |= stateFlag;
			}
		}

		internal void SetDecodeState(DecodeStates stateFlag, DecodeStates resetStateFlag)
		{
			DecodeStateMask |= stateFlag;
			ResetDecodeStateMask(resetStateFlag);
		}

		internal void ResetDecodeStateMask(DecodeStates stateFlag)
		{
			DecodeStateMask &= ~stateFlag;
		}

		internal void ResetDecodeStateMaskToNone()
		{
			DecodeStateMask = DecodeStates.None;
		}

		internal void PushNodeState(ObxmlNodeState ns)
		{
			m_CurrentNode = ns;
			ns.m_ParentNode = GetLastNodeState();
			if (ns.m_ParentNode != null)
			{
				ns.m_ParentNode.ChildNodesCount++;
				ns.NodeLevel = ns.m_ParentNode.NodeLevel + 1;
				if (ns.m_ParentNode.NodeType == NodeTypes.None)
				{
					ns.m_PrefixWhiteSpaces = ObxmlInstructionState.sXmlWhitespaceNewLine;
				}
			}
			ns.NsIndex = (ulong)m_NsStack.Count();
			LastNodeId++;
			m_NodeStates.Push(ns);
			m_PreviousSibling = null;
			if (ObxmlDecodeContext.m_XMLTypeOpcodeDump && ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BinXML, OracleTraceClassName.ObxmlDecodeState, OracleTraceFuncName.PushNodeState, "(BinXMLOpcodeDump) Node Pushed");
			}
		}

		internal ObxmlNodeState PopNodeState()
		{
			if (m_NodeStates.Count <= 0)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.DecodeStateInvalid));
			}
			m_PreviousSibling = (m_CurrentNode = m_NodeStates.Pop());
			PopNamespace((int)m_CurrentNode.NsIndex);
			if (ObxmlDecodeContext.m_XMLTypeOpcodeDump && ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BinXML, OracleTraceClassName.ObxmlDecodeState, OracleTraceFuncName.PopNodeState, "(BinXMLOpcodeDump) Node Popped");
			}
			return m_CurrentNode;
		}

		internal void PushNamespace(PrefixInfo pInfo)
		{
			m_NsStack.Add(pInfo);
		}

		internal void PopNamespace(int index)
		{
			for (int num = m_NsStack.Count() - 1; num >= index; num--)
			{
				m_NsStack.RemoveAt(num);
			}
		}

		internal string GetNamespace(ulong nsid, TokenTypes tokenType = TokenTypes.NamespaceToken)
		{
			return TokenMap.GetTokenName(Parent.DecodeContext, nsid, tokenType);
		}

		internal ObxmlToken GetNamespaceToken(ulong nsid)
		{
			return TokenMap.GetNamespaceToken(Parent.DecodeContext, nsid);
		}

		internal string GetNamespaceUri(ulong nsid)
		{
			ObxmlToken token = null;
			return TokenMap.GetNamespaceUri(Parent.DecodeContext, nsid, out token);
		}

		internal string GetNamespaceUriForNode(ObxmlNodeState node)
		{
			ObxmlToken token = null;
			return TokenMap.GetNamespaceUri(Parent.DecodeContext, node.m_ElementToken.NamespaceId, out token);
		}

		internal PrefixInfo GetPrefixInfo(ulong pfxid)
		{
			PrefixInfo prefixInfo = null;
			if (m_PrefixTable.ContainsKey((int)pfxid))
			{
				prefixInfo = m_PrefixTable[(int)pfxid];
			}
			if (prefixInfo == null)
			{
				prefixInfo = Parent.GetReservedPrefixInfo((short)pfxid);
			}
			if (prefixInfo == null)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.TokenInvalidPrefix));
			}
			return prefixInfo;
		}

		internal string GetPrefix(short pfxid)
		{
			PrefixInfo prefixInfo = null;
			if (m_PrefixTable.ContainsKey(pfxid))
			{
				prefixInfo = m_PrefixTable[pfxid];
			}
			if (prefixInfo == null && pfxid >= 1 && pfxid <= 6)
			{
				return Parent.GetReservedPrefixInfo(pfxid).Prefix;
			}
			if (prefixInfo == null)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.TokenInvalidPrefix));
			}
			return prefixInfo.Prefix;
		}

		internal PrefixInfo SetPrefix(short pfxid, string prefix, ulong nsid)
		{
			PrefixInfo value = null;
			if (!m_PrefixTable.ContainsKey(pfxid))
			{
				value = new PrefixInfo(Parent.DecodeContext, pfxid, prefix, nsid);
				m_PrefixTable[value.PrefixId] = value;
			}
			else
			{
				m_PrefixTable.TryGetValue(pfxid, out value);
			}
			if (!m_NsPrefixTable.ContainsKey((int)nsid))
			{
				m_NsPrefixTable[(int)nsid] = value;
			}
			return value;
		}

		internal PrefixInfo SetPrefix(PrefixInfo prefixInfo)
		{
			PrefixInfo value = null;
			if (!m_PrefixTable.ContainsKey(prefixInfo.PrefixId))
			{
				value = (m_PrefixTable[prefixInfo.PrefixId] = prefixInfo);
			}
			else
			{
				m_PrefixTable.TryGetValue(prefixInfo.PrefixId, out value);
			}
			if (!m_NsPrefixTable.ContainsKey((int)prefixInfo.Nsid))
			{
				m_NsPrefixTable[(int)prefixInfo.Nsid] = value;
			}
			return value;
		}

		internal ObxmlToken GetToken(ulong tokenId, TokenTypes tokenType)
		{
			if (tokenType == TokenTypes.None)
			{
				return Parent.TokenMap.GetToken(Parent.DecodeContext, tokenId, tryRepository: true);
			}
			return Parent.TokenMap.GetToken(Parent.DecodeContext, tokenId, tokenType);
		}

		internal void SetToken(ObxmlToken token)
		{
			Parent.TokenMap.SetToken(token);
		}

		internal string GetNSPrefix(string uri)
		{
			PrefixInfo prefixInfo = null;
			for (int i = 0; i < m_NsStack.Count; i++)
			{
				prefixInfo = m_NsStack[i];
				if (prefixInfo.Uri == uri)
				{
					return prefixInfo.Prefix;
				}
			}
			prefixInfo = null;
			foreach (int key in m_PrefixTable.Keys)
			{
				prefixInfo = m_PrefixTable[key];
				if (prefixInfo.Uri == uri)
				{
					return prefixInfo.Prefix;
				}
			}
			foreach (short key2 in ObxmlDecoder.ReservedNSTable.Keys)
			{
				if (ObxmlDecoder.ReservedNSTable[key2] == uri)
				{
					return ObxmlDecoder.ReservedNSTable[key2];
				}
			}
			return null;
		}

		internal string GetNSPrefix(ulong nsid)
		{
			PrefixInfo value = null;
			for (int i = 0; i < m_NsStack.Count; i++)
			{
				value = m_NsStack[i];
				if (value.Nsid == nsid)
				{
					return value.Prefix;
				}
			}
			if (m_NsPrefixTable.TryGetValue((int)nsid, out value) && value != null)
			{
				return value.Prefix;
			}
			string result = null;
			if (ObxmlDecoder.ReservedNSPrefixTable.ContainsKey((short)nsid))
			{
				result = ObxmlDecoder.ReservedNSPrefixTable[(short)nsid];
			}
			return result;
		}

		internal long WriteTextToOutput(string text)
		{
			return m_RequestObject.m_RequestOutput.WriteTextOutput(text);
		}

		internal long WriteInputToOutput(int lengthToCopyFromInput, bool useReplaceChar = true)
		{
			ObxmlOutputObject requestOutput = m_RequestObject.m_RequestOutput;
			Conv.DelegateReplaceCharsInSB replaceDelegate = null;
			if (useReplaceChar)
			{
				replaceDelegate = StringExtensions.Replace;
			}
			return requestOutput.WriteTextOutput(m_BinXmlStream, lengthToCopyFromInput, replaceDelegate);
		}

		internal long WriteTokenOrData(bool initTokenOrDataLength)
		{
			initTokenOrDataLength = true;
			ObxmlOutputObject requestOutput = m_RequestObject.m_RequestOutput;
			long num = 0L;
			if (m_CurrentInstruction.m_TextOrTokenData != null && m_CurrentInstruction.m_TokenOrDataLength > 0)
			{
				num = requestOutput.WriteTextOutput(m_CurrentInstruction.m_TextOrTokenData, (int)m_CurrentInstruction.m_TokenOrDataOffset, (int)m_CurrentInstruction.m_TokenOrDataLength);
				if (initTokenOrDataLength)
				{
					m_CurrentInstruction.m_TokenOrDataLength = m_CurrentInstruction.m_TextOrTokenData.Length;
				}
				m_CurrentInstruction.ResetTextOrTokenDataLength(num);
			}
			return num;
		}

		internal int WriteCsxBytes(bool initCsxDataLength)
		{
			initCsxDataLength = true;
			ObxmlOutputObject requestOutput = m_RequestObject.m_RequestOutput;
			long num = 0L;
			if (!string.IsNullOrEmpty(m_CurrentInstruction.m_CsxDataText))
			{
				if (initCsxDataLength)
				{
					m_CurrentInstruction.m_CsxDataLength = m_CurrentInstruction.m_CsxDataText.Length * 2;
				}
				num = requestOutput.WriteTextOutput(m_CurrentInstruction.m_CsxDataText, (int)m_CurrentInstruction.m_CsxDataOffset) * 2;
				m_CurrentInstruction.ResetCsxDataLength((int)num);
			}
			return (int)num;
		}
	}
}
